package com.rd.emf.geneditor.view.editors.generic;

import java.util.List;
import java.util.Map;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.IMessage;
import org.eclipse.ui.forms.IMessageManager;
import org.eclipse.ui.forms.ManagedForm;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;

import com.rd.emf.geneditor.model.OawFacade;
import com.rd.emf.geneditor.view.ImageRegistry;

public class EMFGenericEditor extends EMFEcoreEditor implements ChangeListener {

	public static final String EDITOR_ID = "com.rd.genericeditor";

	private static final String ESTRUCTURALFEATURE_KEY = EcorePackage.Literals.ESTRUCTURAL_FEATURE.getName();
	private ManagedForm managedForm;
	private EEMasterDetailsBlock mdBlock;

	private OawFacade facade;
	private ReflectiveItemProviderAdapterFactory reflectiveItemProvider;

	public EMFGenericEditor() {
		super();
		// editingDomain already created by superclass
		ImageRegistry.getDefault().addChangeListener(this);
		reflectiveItemProvider = new ReflectiveItemProviderAdapterFactory();
	}

	@Override
	public void dispose() {
		super.dispose();
		ImageRegistry.getDefault().removeChangeListener(this);
	}

	/**
	 * Model is already created by superclass. Provides a container for EMF's TreeViewer (currentViewer)
	 * 
	 * @see org.eclipse.ui.part.MultiPageEditorPart#createPageContainer(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	protected Composite createPageContainer(Composite parent) {
		parent.setLayout(new FillLayout());
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());
		ScrolledForm form = new ScrolledForm(parent) {
			@Override
			public void reflow(boolean flushCache) {
				// super.reflow(flushCache);
			}
		};
		form.setExpandHorizontal(true);
		form.setExpandVertical(true);
		form.setBackground(toolkit.getColors().getBackground());
		form.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
		form.setFont(JFaceResources.getHeaderFont());
		toolkit.adapt(parent);
		managedForm = new ManagedForm(toolkit, form);
		managedForm.getForm().setText("Generic Editor - " + getFile().getName());
		managedForm.getToolkit().decorateFormHeading(managedForm.getForm().getForm());
		managedForm.getForm().getForm().setToolBarVerticalAlignment(SWT.TOP);
		managedForm.getForm().getForm().addMessageHyperlinkListener(new HyperlinkAdapter() {
			@Override
			public void linkActivated(HyperlinkEvent event) {
				try {
					Object eventData = event.getHref();
					if (eventData instanceof IMessage[]) {
						final IMessage[] messages = (IMessage[]) eventData;

						getSite().getShell().getDisplay().syncExec(new Runnable() {
							public void run() {
								Object object = null;
								Control c = null;
								for (IMessage message : messages) {
									object = message.getKey();
									if (object != null) {
										getViewer().setSelection(new StructuredSelection(object), true);
									}
									if (message.getData() instanceof Map<?, ?>) {
										EStructuralFeature f = (EStructuralFeature) ((Map<?, ?>) message.getData())
												.get(ESTRUCTURALFEATURE_KEY);
										if (f != null) {
											c = mdBlock.findControl(ESTRUCTURALFEATURE_KEY, f);
										}
									}
									break;
								}

								if (c != null && !c.isDisposed()) {
									c.forceFocus();
								}
							}
						});
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		mdBlock = new EEMasterDetailsBlock(new EEDetailsPageProvider(this)) {
			@Override
			protected void createMoreToolBarActions(IToolBarManager toolBarManager) {
				Action action = new Action("Check") {
					@Override
					public void run() {
						checkModel();
					}
				};
				action.setImageDescriptor(com.rd.emf.geneditor.EMFGenericEditorPlugin
						.getImageDescriptor("icons/complete_task.gif"));
				toolBarManager.add(action);
			}
		};
		mdBlock.createContent(managedForm);

		final Composite c = (Composite) mdBlock.getMasterSectionPart().getSection().getClient();
		//
		this.addSelectionChangedListener(new ISelectionChangedListener() {

			public void selectionChanged(SelectionChangedEvent event) {
				if (event.getSelection() instanceof TreeSelection && !event.getSelection().isEmpty())
					managedForm.fireSelectionChanged(mdBlock.getMasterSectionPart(), event.getSelection());
			}

		});
		return c;
	}

	@Override
	public void createPages() {
		super.createPages();
	}

	@Override
	public void createModel() {
		try {
			super.createModel();
			// checkModel();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void doSave(IProgressMonitor progressMonitor) {
		try {
			checkModel();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			super.doSave(progressMonitor);
		}
	}

	/**
	 * 
	 */
	public void checkModel() {
		final List<MessageData> messages = new ModelChecker().check(getEditingDomain().getResourceSet(), getFile());
		getSite().getShell().getDisplay().asyncExec(new Runnable() {

			public void run() {
				IMessageManager messageManager = managedForm.getMessageManager();
				messageManager.removeMessages();
				messageManager.setAutoUpdate(false);
				for (MessageData md : messages) {
					messageManager.addMessage(md.getKey(), md.getMessage(), md.getData(), md.getStatus());
				}
				messageManager.update();
				messageManager.setAutoUpdate(true);
			}
		});
	}

	public IFile getFile() {
		return (IFile) getEditorInput().getAdapter(IFile.class);
	}

	public ReflectiveItemProviderAdapterFactory getReflectiveItemProviderAdapterFactory() {
		return reflectiveItemProvider;
	}

	public void stateChanged(ChangeEvent e) {
		Display.getDefault().asyncExec(new Runnable() {

			public void run() {
				currentViewer.refresh();
			}
		});
	}

	public OawFacade getOawFacade() {
		return facade;
	}

}
